using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using TradeSea;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TradeSea
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class MainGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        TSContentManager Manager;

        DebugConsole DConsole;

        public static World GameWorld = new World(); //contains only wind and air density, should be server side and stuff I guess
                                                     // Joshua.S - not quite, it's client side though all clients have the same seed
        public static Boat playerboat; //temp
        Ocean ocean;
        Model boat;

        Texture2D compass;
        Texture2D compassneedle;
        Texture2D windvane;
        Texture2D windneedle;
        Texture2D speedo;
        Texture2D speedoneedle;

        Rectangle compassLoc;
        Rectangle needleLoc;
        Rectangle windvaneLoc;
        Rectangle windneedleLoc;
        Rectangle speedoLoc;
        Rectangle speedoneedleLoc;

        Sky sky;
        Terrain island;
        int terrianHeight = 200;
        int terrianCellSize = 80;
        Matrix projection;
        Compass Compass = new Compass();
        public Shop shop;

        VertexPositionColor[] testGrid = new VertexPositionColor[6]; //tesgrid vertices
        Vector3 testGridLoc = new Vector3(0, -30, 0);
        BasicEffect basicEffect; //used for testgrid

        public string playerName;
        SaveGame saveGame = new SaveGame();

        Camera currentCamera; //The camera being used for draw calls
        TestCamera tCamera; //A test camera
        FPCamera fpBoatCamera; //A first person camera on the player boat
        MouseOrbitCamera mOCamera;
        List<Camera> CameraList = new List<Camera>(); //durrr
        public Inventory playerInventory = new Inventory();
        Fishing fishing;
        int CameraIndex = 0; //index of current camera being used

        public static Dictionary<int, Boat> OtherBoats = new Dictionary<int, Boat>();

        public string GetAppDir()
        {
            return Path.GetDirectoryName(Environment.CurrentDirectory);
        }

        public MainGame(bool fullScreen, string playerName, Inventory playerInventory, SaveGame saveGame)
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferMultiSampling = true;
            Content.RootDirectory = "Content";

            if (fullScreen)
            {
                this.graphics.IsFullScreen = true;
                this.graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
                this.graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            }
            this.playerName = playerName;
            this.playerInventory = playerInventory;
            this.saveGame = saveGame;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            TradeSeaNetClient.Init();
            base.Initialize();
            //hori lines
            basicEffect = new BasicEffect(graphics.GraphicsDevice);
            basicEffect.LightingEnabled = false;
            basicEffect.VertexColorEnabled = true;
            basicEffect.Alpha = 1.0f;

            shop = new Shop(this, spriteBatch, Manager, playerInventory);
            tCamera = new TestCamera(new Vector3(70, 20, 0), Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio, 1.0f, 10000.0f), new Vector3(0));
            fpBoatCamera = new FPCamera(new Vector3(80, 80, 80), Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(65.0f), GraphicsDevice.Viewport.AspectRatio, 0.5f, 10000.0f), GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2, 1);
            mOCamera = new MouseOrbitCamera(30, Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(65.0f), GraphicsDevice.Viewport.AspectRatio, 0.5f, 10000.0f), GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2, 1);
            CameraList.Add(tCamera);
            CameraList.Add(fpBoatCamera);
            CameraList.Add(mOCamera);
            currentCamera = tCamera;

            //wind and compass rectangles
            compassLoc = new Rectangle(this.GraphicsDevice.Viewport.Width - (this.GraphicsDevice.Viewport.Width / 7), this.GraphicsDevice.Viewport.Height - (this.GraphicsDevice.Viewport.Width / 7), (this.GraphicsDevice.Viewport.Width / 7), (this.GraphicsDevice.Viewport.Width / 7));
            needleLoc = new Rectangle(this.GraphicsDevice.Viewport.Width - (this.GraphicsDevice.Viewport.Width / 14), this.GraphicsDevice.Viewport.Height - (this.GraphicsDevice.Viewport.Width / 14), (this.GraphicsDevice.Viewport.Width / 5), (this.GraphicsDevice.Viewport.Width / 5));
            windvaneLoc = new Rectangle(this.GraphicsDevice.Viewport.Width - (this.GraphicsDevice.Viewport.Width / 7), 0 , (this.GraphicsDevice.Viewport.Width / 7), (this.GraphicsDevice.Viewport.Width / 7));
            windneedleLoc = new Rectangle(this.GraphicsDevice.Viewport.Width - (this.GraphicsDevice.Viewport.Width / 14), 0 + (this.GraphicsDevice.Viewport.Width / 14), (this.GraphicsDevice.Viewport.Width / 5), (this.GraphicsDevice.Viewport.Width / 5));
            speedoLoc = new Rectangle(0, this.GraphicsDevice.Viewport.Height - (this.GraphicsDevice.Viewport.Width / 5), (this.GraphicsDevice.Viewport.Width / 5), (this.GraphicsDevice.Viewport.Width / 5));
            speedoneedleLoc = new Rectangle(speedoLoc.Width / 2, this.GraphicsDevice.Viewport.Height, (this.GraphicsDevice.Viewport.Width / 5), (this.GraphicsDevice.Viewport.Width / 5));
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            this.Manager = new TSContentManager(Content, this);

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //sky stuff
            float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height;
            float fov = MathHelper.PiOver4 * aspectRatio * 3 / 4;
            projection = Matrix.CreatePerspectiveFieldOfView(fov, aspectRatio, 0.1f, 10000.0f);
            sky = new Sky(this.GraphicsDevice, this.Content);
            sky.LoadContent();

            //terrian stuff
            island = new Terrain(Content.Load<Texture2D>("heightMap"), terrianCellSize, terrianHeight, Content.Load<Texture2D>("darkblue"), 6, new Vector3(1, -1, 0), GraphicsDevice, Content);

            boat = Content.Load<Model>("sailingship");
            boat.Bones[0].Transform = boat.Bones[0].Transform * Matrix.CreateRotationX(-MathHelper.PiOver2) * Matrix.CreateRotationY(MathHelper.Pi);
            playerboat = new Boat(this, boat); //create boat
            ClientBoats.owner = this;
            ClientBoats.boatModel = boat;
            ocean = new Ocean(Content, this.GraphicsDevice);
            Model oceanMesh = Content.Load<Model>("ocean2");
            Effect oceanEffect = Content.Load<Effect>("OceanShader");

            compass = Content.Load<Texture2D>("compass");
            compassneedle = Content.Load<Texture2D>("needle");
            windvane = Content.Load<Texture2D>("wind vane");
            windneedle = Content.Load<Texture2D>("windneedle");
            speedo = Content.Load<Texture2D>("speedo");
            speedoneedle = Content.Load<Texture2D>("speedo2arrow");

            ocean.LoadOcean(graphics, oceanMesh, oceanEffect);


            fishing = new Fishing(playerInventory);

            //ContentManager contentManager = new ContentManager(this.Services, @"Content\");
            //So ive added some audio to the game, but for some reasom it says
            //cant find file, where ive clearly added it to the content folder
            //just left the error in so u guys could have a look/
            //soundEffect = contentManager.Load<SoundEffect>("TradeSeaOceanSounds");
            //soundEffect.Play();
            try
            {
                Song song = Content.Load<Song>("ocean sounds");
                MediaPlayer.Play(song);
                MediaPlayer.IsRepeating = true;
            }
            catch (Exception)
            {
                Console.WriteLine("No Sound Device Found - Sound is Off");
            }

            DConsole = new DebugConsole(this, spriteBatch, Manager);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            // TODO: Add your update logic here
            if (DConsole.ConsoleActive == true)  //pauses game when accessing console window.
            {
                DConsole.Update();
            }
            else if (shop.openShop == true) //pauses game when accessing shop
            {
                shop.UpdateShop();
            }
            else //otherwise updates all.
            {
                bool collision = island.boatCollision(playerboat.Location);

                if (collision == true)
                {
                    playerboat.Location = new Vector3(0, 0, 0);
                    shop.openShop = true;
                }

                if (playerboat.Location.X <= terrianCellSize * 150 && playerboat.Location.X >= terrianCellSize * 100 && playerboat.Location.Z <= terrianCellSize * 150 && playerboat.Location.Z >= terrianCellSize * 100)
                {
                    playerInventory.addToInventory("1000gold");
                    Console.WriteLine("You found treasure!");
                }
                float deltaTime = gameTime.ElapsedGameTime.Milliseconds / 1000f; //change in time from last frame
                KeyboardState kstate = Keyboard.GetState();
                MouseState mstate = Mouse.GetState();
                testGridLoc = playerboat.Location;

                // Allows the game to exit
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    this.Exit();

                if (kstate.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D1)) //change camera
                    CameraIndex = 0;
                else if (kstate.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D2))
                    CameraIndex = 1;
                else if (kstate.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D3))
                    CameraIndex = 2;
                currentCamera = CameraList[CameraIndex];
                if (kstate.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.F1))
                {
                    saveGame.Save(GetAppDir(), playerName, playerInventory);
                }
                DConsole.Update();


                GameWorld.Update(gameTime);
                playerboat.Update(kstate, GameWorld, deltaTime);

                ClientBoats.Update(GameWorld, deltaTime);

                tCamera.Update(kstate, playerboat.Location);
                fpBoatCamera.Update(playerboat.FPCameraLocAngle, new Vector2(mstate.X, mstate.Y));
                mOCamera.Update(playerboat.Location + new Vector3(0, 5, 0), new Vector2(mstate.X, mstate.Y));
                if (currentCamera == fpBoatCamera || currentCamera == mOCamera)
                    Mouse.SetPosition(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);

                ocean.UpdateOcean(gameTime, playerboat.Location);

                testGrid[0].Position = new Vector3(0, 5, 0);
                testGrid[1].Position = new Vector3(0, 5, 0) + GameWorld.GetWind(playerboat.Location) * 5;
                testGrid[2].Position = new Vector3(0, 5, 0);
                testGrid[3].Position = new Vector3(0, 5, 0) + GameWorld.GetWind(playerboat.Location) * 5 - playerboat.Velocity * 5;

                playerboat.Location = new Vector3(playerboat.Location.X, ocean.getOceanHeightAtPoint(playerboat.Location) + 1, playerboat.Location.Z);

                Compass.setCompass(playerboat.getCompassHeading());
                fishing.updateFishing(kstate);
                //saveGame.Update(kstate, playerName, playerboat.Location, playerInventory);
            }

        }
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            GraphicsDevice.DepthStencilState = DepthStencilState.None;

            sky.Draw(this.GraphicsDevice, currentCamera.getProjection(), currentCamera.getView(), currentCamera.Location);

            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            island.Draw(currentCamera.getView(), currentCamera.getProjection());



            playerboat.Draw(this.GraphicsDevice, currentCamera.getProjection(), currentCamera.getView());

            ClientBoats.Draw(this.GraphicsDevice, currentCamera);

            ocean.DrawOcean(gameTime, currentCamera.getView(), currentCamera.getProjection(), graphics);
            
            basicEffect.World = Matrix.CreateTranslation(testGridLoc);
            basicEffect.View = currentCamera.getView();
            basicEffect.Projection = currentCamera.getProjection();

            basicEffect.CurrentTechnique.Passes[0].Apply();

            GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, testGrid, 0, 2, VertexPositionColor.VertexDeclaration);


            spriteBatch.Begin();

            spriteBatch.Draw(compass, compassLoc, Color.White);
            spriteBatch.Draw(windvane, windvaneLoc, Color.White);
            //spriteBatch.Draw(speedo, speedoLoc, Color.White);
            //spriteBatch.Draw(speedoneedle, speedoneedleLoc, Color.White);

            Vector2 org = new Vector2(compassneedle.Width/2, compassneedle.Height/2);
            Vector2 org2 = new Vector2(windneedle.Width / 2, windneedle.Height / 2);

            Rectangle cnsourceRectangle = new Rectangle(0, 0, compassneedle.Width, compassneedle.Height);
            Rectangle wnsourceRectangle = new Rectangle(0, 0, windneedle.Width, windneedle.Height);
            Rectangle snsourceRectangle = new Rectangle(0, 0, speedoneedle.Width, speedoneedle.Height);
            

            spriteBatch.Draw(compassneedle, needleLoc, cnsourceRectangle, Color.White, playerboat.getCompassHeading(), org, SpriteEffects.None, 1 );
            spriteBatch.Draw(windneedle, windneedleLoc, wnsourceRectangle, Color.White,(float) Math.Acos(Vector3.Dot(Vector3.Forward, Vector3.Normalize(GameWorld.GetWind(playerboat.Location)))), org2, SpriteEffects.None, 1);
            //spriteBatch.Draw(compassneedle, speedoneedleLoc, snsourceRectangle, Color.White, playerboat.Speed + 90, org, SpriteEffects.None, 1);

            /*spriteBatch.DrawString(Manager.ConsoleFont, "Welcome to ye'olde Tradesea", new Vector2(10, 10), Color.Black);
            if (TradeSeaShared.Singiltons.IsListen)
            {
                spriteBatch.DrawString(Manager.ConsoleFont, "AHOY! I be a ye'olde Server", new Vector2(10, 50), Color.Green);
            }
            else
            {
                spriteBatch.DrawString(Manager.ConsoleFont, "AHOY! I be a ye'olde Client", new Vector2(10, 50), Color.Red);
            }*/

           // spriteBatch.DrawString(Manager.ConsoleFont, Vector3.Dot(Vector3.Forward, GameWorld.GetWind(playerboat.Location)), new Vector2(10, 50), Color.Red);

            fishing.drawFishing(spriteBatch, Manager);
            saveGame.Draw(spriteBatch, Manager, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);

            shop.drawShop();

            DConsole.Draw();

            spriteBatch.End();

            base.Draw(gameTime);
        }
        //copied method

    }
}
